<template>
    <n-card class="wh-100%">
        <template #header>
            <div class="w-full flex justify-between">
                <div class="font-size-4">股票预测情况</div>
                <div class="flex gap-2.5">
                    <!-- 选择股票 -->
                    <n-select
                        v-model:value="selectedStock"
                        :options="stockOptions"
                        :disabled="activeTab === 'table'"
                        @update:value="handleChangeStock"
                        placeholder="选择股票"
                        class="w-150px"
                    />
                    <!-- 选择图表类型 -->
                    <n-select
                        v-model:value="chartType"
                        :options="chartOptions"
                        :disabled="activeTab === 'table'"
                        @update:value="handleChangeChartType"
                        class="w-150px"
                        placeholder="选择图表类型"
                    />
                    <!-- 切换图表或表格 -->
                    <n-tabs
                        size="small"
                        type="segment"
                        class="w-60"
                        v-model:value="activeTab"
                    >
                        <n-tab name="chart" label="图表" />
                        <n-tab name="table" label="表格" />
                    </n-tabs>
                </div>
            </div>
        </template>
        <div v-if="currentStockData.length === 0" class="flex-center wh-100%">
            <n-result
                status="418"
                title="暂无数据"
                description="一切尽在不言中"
            >
            </n-result>
        </div>
        <div v-else class="wh-100%">
            <div v-show="activeTab === 'chart'">
                <div ref="chartRef" class="w-full h-500px"></div>
            </div>
            <n-data-table
                v-show="activeTab === 'table'"
                :columns="stockPredictionColumns"
                :data="currentStockData"
                max-height="60vh"
            ></n-data-table>
        </div>
    </n-card>
</template>

<script lang="ts" setup>
import { ref, reactive, onMounted, watch, nextTick } from "vue";

import * as echarts from "echarts";
import { StockPrediction } from "@/types/prediction";

import { stockPredictionColumns } from "@/utils/table-column";
import { SPrediction, getStockPrediction } from "@/service/api/predict";

const props = defineProps<{
    timestamp: number;
}>();

// 响应式数据
const selectedStock = ref<"moutai" | "catl" | "icbc">("moutai");
const chartType = ref<"candlestick" | "volume">("candlestick");
const activeTab = ref<"chart" | "table">("chart");

// 股票选项
const stockOptions = [
    { label: "贵州茅台", value: "moutai" },
    { label: "宁德时代", value: "catl" },
    { label: "工商银行", value: "icbc" },
];

// 图表类型选项
const chartOptions = [
    { label: "股价走势", value: "candlestick" },
    { label: "成交量", value: "volume" },
];

const chartRef = ref<HTMLElement | null>(null);
let chartInstance: echarts.ECharts | null = null;

const stockData = reactive({
    moutai: new Map<number, StockPrediction[]>(),
    catl: new Map<number, StockPrediction[]>(),
    icbc: new Map<number, StockPrediction[]>(),
});
const currentStockData = ref<StockPrediction[]>([]);

// 更新图表数据
const updateChart = () => {
    if (chartInstance) {
        chartInstance.dispose();
        chartInstance = null;
    }

    if (chartRef.value) {
        chartInstance = echarts.init(chartRef.value);
    }

    const date = currentStockData.value.map((item) => item.date);

    // 提取蜡烛图数据
    const candleData = currentStockData.value.map((item) => [
        item.open_price,
        item.close_price,
        item.low,
        item.high,
    ]);

    // 提取成交量条形图数据
    const volumeData = currentStockData.value.map((item) => item.volume);

    let option;
    if (chartType.value === "candlestick") {
        // k线图配置
        option = {
            tooltip: {
                trigger: "axis",
                axisPointer: {
                    type: "cross",
                    crossStyle: {
                        color: "#999",
                    },
                },
                formatter: (params: any) => {
                    const param = params[0];
                    const date = param.name;
                    const [open, close, low, high] = param.data.slice(1);
                    return `
                        <div>日期: ${date}</div>
                        <div>开盘价: ${open}</div>
                        <div>收盘价: ${close}</div>
                        <div>最低价: ${low}</div>
                        <div>最高价: ${high}</div>
                    `;
                },
            },
            xAxis: {
                type: "category",
                name: "日期",
                data: date,
                axisLabel: {
                    rotate: 45,
                },
            },
            yAxis: {
                scale: true,
                name: "价格(元)",
            },
            series: [
                {
                    type: "candlestick",
                    data: candleData,
                },
            ],
        };
    } else {
        // 成交量折线图配置
        option = {
            tooltip: {
                trigger: "axis",
                axisPointer: {
                    type: "line",
                    lineStyle: {
                        color: "#999",
                    },
                },
                formatter: (params: any) => {
                    const param = params[0];
                    const date = param.name;
                    const volume = param.data;
                    return `
                        <div>日期: ${date}</div>
                        <div>成交量: ${volume} 万股</div>
                    `;
                },
            },
            xAxis: {
                type: "category",
                name: "日期",
                data: currentStockData.value.map((item) => item.date),
                axisLabel: {
                    rotate: 45,
                },
            },
            yAxis: {
                name: "成交量(万股)",
                type: "value",
            },
            series: [
                {
                    type: "bar",
                    data: volumeData,
                },
            ],
        };
    }

    chartInstance?.setOption(option);
};

const handleResize = () => {
    if (chartInstance) {
        chartInstance.resize();
    }
};

const handleQuery = async () => {
    try {
        const res = await getStockPrediction(props.timestamp);
        const data = res.data as SPrediction;
        for (const key in data) {
            stockData[key as keyof SPrediction].set(
                props.timestamp,
                data[key as keyof SPrediction]
            );
        }
        currentStockData.value = stockData[selectedStock.value].get(
            props.timestamp
        ) as StockPrediction[];
    } catch (err) {
        for (const key in stockData) {
            stockData[key as keyof SPrediction].set(props.timestamp, []);
        }
        currentStockData.value = [];
        window.NMessage.error((err as Error).message);
    }
};

watch(
    () => props.timestamp,
    async () => {
        if (stockData[selectedStock.value].has(props.timestamp)) {
            currentStockData.value = stockData[selectedStock.value].get(
                props.timestamp
            ) as StockPrediction[];
        } else {
            await handleQuery();
        }
        nextTick(() => {
            updateChart();
        });
    }
);

onMounted(async () => {
    await handleQuery();
    // 更新图表
    updateChart();

    // 监听窗口大小, 当出现变化时重新绘制图像
    window.addEventListener("resize", handleResize);
});

// 切换股票
const handleChangeStock = (value: "moutai" | "catl" | "icbc") => {
    selectedStock.value = value;
    currentStockData.value = stockData[value].get(
        props.timestamp
    ) as StockPrediction[];
    updateChart();
};

const handleChangeChartType = (value: "candlestick" | "volume") => {
    chartType.value = value;
    updateChart();
};

const getCurrentData = () => {
    if (currentStockData.value.length === 0) {
        return null;
    }
    return {
        moutai: stockData.moutai.get(props.timestamp),
        catl: stockData.catl.get(props.timestamp),
        icbc: stockData.icbc.get(props.timestamp),
    };
};

const handleReload = async () => {
    await handleQuery();
    nextTick(() => {
        updateChart();
    });
};

defineExpose({
    getCurrentData,
    handleReload,
});
</script>

<style scoped></style>
